/*
 * board.cpp
 * This class is used to define the game board.
 *
 *  Created on: 19/01/2009
 *      Author: smaxll
 */

#include "SDL.h"
#include "SDL_opengl.h"
#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <cmath>
#include "math.h"

#include "board.hpp"
#include "game.hpp"

namespace {
    /// the board size, default is 20*20
    unsigned int size = 20;

    std::vector<chessPieceType> boardRow(size, NULLPIECE);
    std::vector< std::vector<chessPieceType> > boardInfo(size, boardRow);

    /// margin size measured in pixels
//    unsigned int marginPixels;
    double squareSize; /// each board square, in world coordinate

    double chessRadius;

    int player = 0;
}

namespace board {

    /** Initialize the board */
    bool init(){
//        marginPixels = game_controller::get_screen_height()/22 + 1; /// calculate the margin of board
        squareSize = (double)20/(double)size;
        chessRadius = (double)10/(double)size;

        change_size(20);
        player = BLACK_TURN;
        return true;
    }


    void draw_chess_pieces();

    /** draw the main board **/
    bool draw(){

        /** Draw the board */
        glColor3f( 1.0, 1.0, 1.0 );
        glBegin(GL_LINE_STRIP);
            glVertex2f(0.0, 0.0);
            glVertex2f(20.0, 0.0);
            glVertex2f(20.0, 20.0);
            glVertex2f(0, 20.0);
            glVertex2f(0,0);
        glEnd();

        glBegin(GL_LINES);
            for(unsigned int i=1; i<size; i++){
                glVertex2f(0.0, i*squareSize);
                glVertex2f(20.0, i*squareSize);
                glVertex2f(i*squareSize, 0);
                glVertex2f(i*squareSize, 20.0);
            }
        glEnd();

        draw_chess_pieces();

        return true;
    }

    /** size for each square, changed as the board size changes */
//    double get_square_size(){
//        return squareSize;
//    }


    /**
     * Change the board size
     */
    bool change_size(unsigned int newSize){
        size = newSize;

        /// restart game
        game_controller::close_game();

        /// reset the board information. set to NULL for each chess piece
        std::vector< std::vector<chessPieceType> >::iterator board_iter;
        std::vector<chessPieceType>::iterator row_iter;

        for(board_iter = boardInfo.begin(); board_iter != boardInfo.end(); board_iter++){
            for(row_iter = (*board_iter).begin(); row_iter != (*board_iter).end(); row_iter++){
                *row_iter = NULLPIECE;
            }
        }

        // recompute the square size
        squareSize = 20.0/(float)size;

        return true;
    }

    /**
     * Check if the mouse position (posX, posY) is inside the board square
     * @param posX x object coordinate
     * @param posY y object coordinate
     * @return true if the position is inside the board.
     */
    bool is_inside_board(double posX, double posY){

        /** check if the mouse position inside the screen */
        if((posX > 20) || (posX < 0)){
            return false;
        }

        if((posY > 20) || (posY < 0)) {
            return false;
        }

        return true;
    }

    /**
     * locate the board position based on the given mouse coordinate.
     * @param posX posY are the given mouse position.
     * @return the index for the position in the boardInfo vector matrix.
     */
    /*
    std::pair<unsigned int, unsigned int> locate(unsigned int posX, unsigned int posY){
        std::pair<unsigned int, unsigned int> matrixIndex;

        matrixIndex.first = (posX - marginPixels)/squarePixels;
        matrixIndex.second = (posY - marginPixels)/squarePixels;

        return matrixIndex;
    }
    */

    /**
     * Draw a solid circle centered at (X,Y)
     */
    void draw_circle(double centerX, double centerY){
        float delta_theta = 0.1;
        float PI = 3.14;

        glBegin( GL_POLYGON ); // OR GL_LINE_LOOP

        for( float angle = 0; angle < 2*PI; angle += delta_theta )
            glVertex3f( centerX + chessRadius*cos(angle), centerY + chessRadius*sin(angle), 0 );

        glEnd();
    }


    /**
     * Draw a chess piece on the board
     * @param posX posY: the position where a chess piece is drawn, with world coordinates
     */
    void draw_chess_pieces(){
        for(unsigned i=0; i<size; i++){
            for(unsigned jj=0; jj<size; jj++){
                if(boardInfo[i][jj] == BLACK){
                    glColor3f(0.0, 0.0, 0.0);
                    draw_circle(i*squareSize + chessRadius, jj*squareSize + chessRadius );
                } else if(boardInfo[i][jj] == WHITE){
                    glColor3f(1.0, 1.0, 1.0);
                    draw_circle(i*squareSize + chessRadius, jj*squareSize + chessRadius );
                }
            }
        }

    }

    /**
     * Determine if the move in boardInfo matrix[indexA][indexB] is the final move?
     * The algorithm for checking is to check vertically, horizontally and 2 diagonal.
     * @param indexA
     * @return ture if the game finished with the move, false otherwise.
     */
    bool last_move(int indexA, int indexB){
        int numChess = 1;

        /// Check vertically (up)
        for(int i=1; i<5; i++){
            if((indexB+i) > 19){
                break;
            }
            if(boardInfo[indexA][indexB+i] == boardInfo[indexA][indexB]){
                numChess++;
            }else{
                break;
            }
        }

        /// Check vertically (down)
        for(int i=1; i<5; i++){
            if((indexB-i)<0){
                break;
            }
            if(boardInfo[indexA][indexB-i] == boardInfo[indexA][indexB]){
                numChess++;
            }else{
                break;
            }
        }

        if(numChess >= 5){
             return true;
         }else{
             numChess = 1;
         }

        /// Check horizontally (left)
        for(int i=1; i<5; i++){
            if((indexA-i) < 0){
                break;
            }
            if(boardInfo[indexA-i][indexB] == boardInfo[indexA][indexB]){
                numChess++;
            }else{
                break;
            }
        }

        /// (right)
        for(int i=1; i<5; i++){
            if((indexA+i) > 19){
                break;
            }
            if(boardInfo[indexA+i][indexB] == boardInfo[indexA][indexB]){
                numChess++;
            }else{
                break;
            }
        }

        if(numChess >= 5){
             return true;
         }else{
             numChess = 1;
         }

        /// Check diagonal (left->right)
        for(int i=1; i<5; i++){
            if((indexA-i)<0 || (indexB+i)>19 ){
                break;
            }
            if(boardInfo[indexA-i][indexB+i] == boardInfo[indexA][indexB]){
                numChess++;
            }else{
                break;
            }
        }

        for(int i=1; i<5; i++){
            if((indexB-i)<0 || (indexA+i)>19){
                break;
            }
            if(boardInfo[indexA+i][indexB-i] == boardInfo[indexA][indexB]){
                numChess++;
            }else{
                break;
            }
        }

        if(numChess >= 5){
             return true;
         }else{
             numChess = 1;
         }

        /// Check diagonal (right->left)
        for(int i=1; i<5; i++){
            if((indexB+i) > 19 || (indexA+i) > 19){
                break;
            }
            if(boardInfo[indexA+i][indexB+i] == boardInfo[indexA][indexB]){
                numChess++;
            }else{
                break;
            }
        }

        for(int i=1; i<5; i++){
            if((indexB-i)<0 || (indexA-i)<0){
                break;
            }
            if(boardInfo[indexA-i][indexB-i] == boardInfo[indexA][indexB]){
                numChess++;
            }else{
                break;
            }
        }

        if(numChess >= 5){
            return true;
        }else{
            return false;
        }
    }

    /**
     * Change the board matrix info accordingly.
     * @param posX is the world coordinate of the mouse position. NOTE: not screen coordinates
     * @param posY ....
     */
    void set_chess_piece(double posX, double posY){
        int indexA, indexB; /// board info matrix index

        indexA = posX/squareSize;
        indexB = posY/squareSize;


        /// click on the square where there is a chess piece
        if((boardInfo[indexA][indexB] != NULLPIECE) || (player == NO_TURN)) {
            return;
        }

        if((player == BLACK_TURN) && (boardInfo[indexA][indexB] == NULLPIECE)){
//                std::cout << boardInfo[indexA][indexB] << std::endl;
            boardInfo[indexA][indexB] = BLACK;
//                std::cout << boardInfo[indexA][indexB] << std::endl;
            player = WHITE_TURN;
        } else if ((player == WHITE_TURN) && (boardInfo[indexA][indexB] == NULLPIECE)) {
            boardInfo[indexA][indexB] = WHITE;
            player = BLACK_TURN;
        }

        if ( last_move(indexA, indexB) ){
            if(player == BLACK_TURN){
                std::cout << "WHITE WON " << std::endl;
            } else {
                std::cout << "BLACK WON " << std::endl;
            }
            player = NO_TURN;
        }

//        draw();
    }

}
